package com.midcent.networklib.sftp;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
import com.jcraft.jsch.SftpProgressMonitor;
import com.midcent.networklib.sftp.core.Builder;
import com.midcent.networklib.sftp.core.GetBuilder;
import com.midcent.networklib.sftp.core.PutBuilder;

import java.io.File;

/**
 * Sftp Service
 */
public class SftpUtils {
    private static final String TAG = "SftpService";

    public static final int GET = 0;
    public static final int PUT = 1;
    private static int type = GET;

    private static SftpUtils instance;

    private SftpUtils() {
    }

    public static SftpUtils getInstance() {
        if (instance == null) {
            synchronized (SftpUtils.class) {
                instance = new SftpUtils();
            }
        }
        return instance;
    }

    private Handler mainHandler = new Handler(Looper.getMainLooper());

    public static Builder get(Context context) {
        return new GetBuilder(context);
    }

    public static Builder put(Context context) {
        return new PutBuilder(context);
    }

    private long mMax = 0;
    private long mCount = 0;
    private long mPercent = 0;

    private Builder builder;

    public void setBuilder(Builder builder) {
        this.builder = builder;
    }

    private boolean isStarting = false;

    private MyThread mThread;
    private SftpListener mListener;
    private int errorCount = 0;


    public interface SftpListener {
        void init(int op, String src, String dest, long max);

        void percent(long percent);

        void end(String filePath);

        void error();
    }

    public void execute(SftpListener listener) {
        this.mListener = listener;
        if (mThread != null && mThread.isAlive()) {
            Log.d(TAG, "starting");
            return;
        }

        mThread = new MyThread();
        mThread.start();
    }

    private class MyThread extends Thread {
        @Override
        public void run() {
            super.run();
            errorCount = 0;
            sftpRelease();

            if (!isStarting) {
                Log.d(TAG, "start");
                sftpTransfer();
            }
        }
    }

    Session session;
    Channel channel;
    ChannelSftp sftp;

    private void sftpRelease() {
        if (sftp != null) {
            sftp.disconnect();
            sftp.exit();
            sftp = null;
        }
        if (channel != null) {
            channel.disconnect();
            channel = null;
        }
        if (session != null) {
            session.disconnect();
            session = null;
        }
    }

    private void sftpTransfer() {
        if (builder.type == 0 && new File(builder.dst).exists() && new File(builder.dst).delete()) {
            Log.d(TAG, "delete " + builder.dst + " success");
        }
        try {
            JSch ssh = new JSch();
            session = ssh.getSession(builder.username, builder.host, builder.port);
            // Remember that this is just for testing and we need a quick access, you can add an identity and known_hosts file to prevent
            // Man In the Middle attacks
            java.util.Properties config = new java.util.Properties();
            config.put("StrictHostKeyChecking", "no");
            session.setConfig(config);
            session.setPassword(builder.password);

            session.connect();
            channel = session.openChannel("sftp");
            channel.connect();

            sftp = (ChannelSftp) channel;

            // sftp.cd(directory);
            // If you need to display the progress of the upload, read how to do it in the end of the article
            // use the put method , if you are using android remember to remove "file://" and use only the relative path
            // sftp.put("/storage/0/myfile.txt", "/var/www/remote/myfile.txt");
            // sftp.put("sdcard/ic_launcher.png", "pic_ic_launcher.png");
            // sftp.get("text.tex", "text.txt");

            if (builder.type == 1) {
                sftp.get(builder.src, builder.dst, sftpProgressMonitor);
            } else if (builder.type == 0) {
                sftp.put(builder.src, builder.dst, sftpProgressMonitor);
            }

            channel.disconnect();
            session.disconnect();
        } catch (JSchException | SftpException e) {
            e.printStackTrace();
            try {
                mThread.sleep(1000);
            } catch (InterruptedException exp) {
                exp.printStackTrace();
            }

            ++errorCount;
            if (errorCount < 2 && e.getMessage().contains("No such file")) {
                String url = builder.src;
                url = url.replace(".mp4", ".tmp");
                builder.src = url;
                sftpTransfer();
                return;
            }
            if (mListener != null) {
                mListener.error();
            }
        }
    }

    SftpProgressMonitor sftpProgressMonitor = new SftpProgressMonitor() {
        @Override
        public void init(final int op, final String src, final String dest, final long max) {
            isStarting = true;
            mMax = max;
            mPercent = 0;
            mCount = 0;
            mainHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (mListener != null) {
                        mListener.init(op, src, dest, max);
                    }
                }
            });
        }

        @Override
        public boolean count(long count) {
            mCount += count;

            long percent = mCount * 100 / mMax;
            if (mPercent < percent) {
                mPercent = percent;
                mainHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        if (mListener != null) {
                            mListener.percent(mPercent);
                        }
                    }
                });
            }

            return true;
        }

        @Override
        public void end() {
            isStarting = false;
            mainHandler.post(new Runnable() {
                @Override
                public void run() {
                    try {
                        mThread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if (mListener != null) {
                        mListener.end(builder.dst);
                    }
                }
            });
        }
    };

}
